/**
 * FilterLayer is a canvas, on which various filters can be applied. These filters, for now, will only be drawn on top of
 * the host, therefore leaving the whole canvas transparent.
 * 
 * The puropse of creating this class is to simplify the process of creating and updating filters, which troubles the original version
 * of Indy2 much, because virtually these tasks are so similiar that we soon got boreing at them ourselves. 
 * 
 * Suppose you have an UIComponent who need to have a glow filter and a drop-shadow filter outside its border, then what you do is to write
 * some properties in its CSS defination, such as:
 * 
 * .someComponent{
 * 	filterLayer: ".myGlowFilter", ".myShadowFilter";
 *  ...
 * }
 * 
 * .myGlowFilter{
 * 	kind: ClassReference("flash.filters.GlowFilter");
 * 	blurX: 5;
 * 	blurY: 5;
 *  ...
 * }
 * 
 * .myShadowFilter{
 *  kind: ClassReference("flash.filters.DropShadowFilter");
 * 	instance: 3;
 * 	alpha: 0.9;
 *  ...
 * }
 * 
 * As you can see, you can use the class name for the "kind" property 
 * 
 * Of course, if you don't need any filters, you can always leave outterFilters empty, or even don't define this
 * style at all.
 * 
 * NOTE: the order of filterLayer is exactly the same order the filters being put into the filters stack. So please
 * 		 consider order while filling the stack.
 * 
 * @since Indy2 1.1
 */

package org.delphy.indy2.layers
{
	import flash.display.Graphics;
	import flash.events.Event;
	import flash.filters.BitmapFilter;
	import flash.filters.DropShadowFilter;
	import flash.filters.GlowFilter;
	
	import mx.containers.Canvas;
	import mx.core.UIComponent;
	import mx.styles.CSSStyleDeclaration;
	import mx.styles.StyleManager;
	
	public class FilterLayer extends Canvas
	{
		/**
		 * @protected
		 * The host UIComponent of this canvas
		 */
		protected var _host:UIComponent;
		
		/**
		 * @protected
		 * Filters Stack
		 */
		protected var _filterArray:Array=[];
		public function get filterArray():Array{
			return _filterArray;
		}
		
		//----------------------------------
	    //  Methods
	    //----------------------------------
	    
	    /**
	    * Constructor
	    */		
		public function FilterLayer(host: UIComponent)
		{
			super();
			
			_host=host;			
			
			// This event listener will make sure we do resize when the host is resized
			_host.addEventListener(Event.RESIZE, onHostResize);
		}
		
		/**
		 * @public
		 */
		public function initFilters(layerName:String="filterLayer"):void{
			_filterArray=[];
			
			// If this is empty, then there's nothing we need to do~~~
			if(!_host.getStyle(layerName))
				return;

			var filterStack:Array;
			if(_host.getStyle(layerName) is Array)
				filterStack=_host.getStyle(layerName);
			else
				filterStack=[_host.getStyle(layerName)];
			
			if(filterStack.length==0)
				return;
			
			// However, if there exists anything in the stack,
			// then we have to find out what kind of filters they are, and create them.
			for each(var filterStyleName:String in filterStack){
				// In case users forgot to put "." as a CSS class prefix, we are offering a adjustment here
				if(filterStyleName.charAt(0)!=".")
					filterStyleName="." + filterStyleName;
					
				var filter:BitmapFilter=parseFilter(filterStyleName);
				_filterArray.push(filter);
			}
		}
		
		/**
		 * @protected
		 * 
		 * Create a filter by "kind" and fill its propertites
		 */
		protected function parseFilter(filterStyleName:String):BitmapFilter{
			// First, we will find the CSS style, as defined in filterStyleName
			var filterStyle:CSSStyleDeclaration=StyleManager.getStyleDeclaration(filterStyleName);
			var filterClass:Class=filterStyle.getStyle("kind");
			var filter:BitmapFilter=new filterClass();
			
			// Then, we extract all properties defined in the CSS style:
			var styleFactory:* = new filterStyle.factory();
			for(var styleKey:* in styleFactory){
				// Ingnore "kind" propertity
				if(styleKey as String == "kind")
					continue;
				filter[styleKey] = styleFactory[styleKey];
			}
			
			// A special tweak for DropShadowFilter and GlowFilter
			if(filterClass == DropShadowFilter || filterClass == GlowFilter){
				filter["knockout"]=true;
			}			
			return filter;
		}
				
		/**
		 * @public
		 */
		public function disableFilters():void{
			visible=false;
		}
		
		/**
		 * @public
		 */
		public function enableFilters():void{
			visible=true;
		}
		
		/**
		 * @protected
		 * Invoked when the host is resized
		 */
		protected function onHostResize(evt:Event):void{
			invalidateDisplayList();
		}
		
		//----------------------------------
	    //  Overridden Methods
	    //----------------------------------
	    override protected function createChildren():void{
	    	super.createChildren();
	    	
	    	initFilters();
			
	    	// We create children with the same number of filters. Each child is assigned exactly one filter
	    	for each(var filter:BitmapFilter in _filterArray){
	    		var child:UIComponent=new UIComponent();

	    		child.filters=[filter];
	    		rawChildren.addChild(child);
	    	}
	    }
	    
		override protected function updateDisplayList(unscaledWidth:Number, unscaledHeight:Number):void{
			super.updateDisplayList(unscaledWidth, unscaledHeight);
			
			if(!_host)
				return;
			
			var topLeftRadius:Number;
			var topRightRadius:Number;
			var bottomLeftRadius:Number;
			var bottomRightRadius:Number;
				
			if(getStyle("topLeftRadius"))
				topLeftRadius=getStyle("topLeftRadius");	
			else if(_host.getStyle("topLeftRadius"))
				topLeftRadius=_host.getStyle("topLeftRadius");
			else if(_host.getStyle("cornerRadius"))
				topLeftRadius=_host.getStyle("cornerRadius");
			else
				topLeftRadius=1;

			if(getStyle("topRightRadius"))
				topRightRadius=getStyle("topRightRadius");	
			else if(_host.getStyle("topRightRadius"))
				topRightRadius=_host.getStyle("topRightRadius");
			else if(_host.getStyle("cornerRadius"))
				topRightRadius=_host.getStyle("cornerRadius");
			else
				topRightRadius=1;

			if(getStyle("bottomLeftRadius"))
				bottomLeftRadius=getStyle("bottomLeftRadius");	
			else if(_host.getStyle("bottomLeftRadius"))
				bottomLeftRadius=_host.getStyle("bottomLeftRadius");
			else if(_host.getStyle("cornerRadius"))
				bottomLeftRadius=_host.getStyle("cornerRadius");
			else
				bottomLeftRadius=1;

			if(getStyle("bottomRightRadius"))
				bottomRightRadius=getStyle("bottomRightRadius");	
			else if(_host.getStyle("bottomRightRadius"))
				bottomRightRadius=_host.getStyle("bottomRightRadius");
			else if(_host.getStyle("cornerRadius"))
				bottomRightRadius=_host.getStyle("cornerRadius");
			else
				bottomRightRadius=1;
			
			// Draw something whatever you want to, they are not visible anyway. But you can't just set your fill's alpha 
			// to zero, or else filters would become invisible, too.
			for(var i:uint=0;i<rawChildren.numChildren;i++){
				var child:UIComponent=UIComponent(rawChildren.getChildAt(i));
				var g:Graphics=child.graphics;
				g.clear();
				g.beginFill(0xFF0000,1);
				g.drawRoundRectComplex(0, 0, _host.width, _host.height,topLeftRadius, 
											  topRightRadius, bottomLeftRadius, bottomRightRadius);
				g.endFill();
				child.filters=child.filters;
			}		
		}
	}
}